package cn.lili.modules.permission.serviceimpl;

import cn.hutool.core.text.CharSequenceUtil;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.exception.ServiceException;
import cn.lili.common.security.AuthUser;
import cn.lili.common.security.context.UserContext;
import cn.lili.common.security.enums.SceneEnums;
import cn.lili.common.utils.StringUtils;
import cn.lili.modules.permission.entity.dos.Department;
import cn.lili.modules.permission.entity.dto.DepartmentEditDTO;
import cn.lili.modules.permission.entity.dto.DepartmentSearchParams;
import cn.lili.modules.permission.entity.vo.DepartmentVO;
import cn.lili.modules.permission.mapper.DepartmentMapper;
import cn.lili.modules.permission.service.DepartmentService;
import cn.lili.mybatis.util.SceneHelp;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.transaction.annotation.ShardingTransactionType;
import org.apache.shardingsphere.transaction.core.TransactionType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 部门 业务层实现
 *
 * @author Chopper
 * @since 2020/11/17 3:47 下午
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Department> implements DepartmentService {

    private static final String DEFAULT_PARENT_ID = "0";

    @Override
    @Transactional
    @ShardingTransactionType(TransactionType.BASE)
    public void deleteDepartments(List<String> departmentIds) {
        this.removeByIds(departmentIds);
    }

    @Override
    public List<DepartmentVO> tree(DepartmentSearchParams departmentSearchParams) {
        try {
            AuthUser currentUser = Objects.requireNonNull(UserContext.getCurrentUser());
            QueryWrapper<Department> queryWrapper = departmentSearchParams.wrapper();

            //处理查询条件
            if (SceneEnums.MANAGER.equals(currentUser.getScene()) && CharSequenceUtil.isNotEmpty(departmentSearchParams.getScene())) {
                queryWrapper.eq(CharSequenceUtil.isNotEmpty(departmentSearchParams.getScene()) && SceneEnums.MANAGER.equals(currentUser.getScene()),
                        "scene", departmentSearchParams.getScene());
                queryWrapper.eq(CharSequenceUtil.isNotEmpty(departmentSearchParams.getStoreId()) && SceneEnums.MANAGER.equals(currentUser.getScene()),
                        "extend_id", departmentSearchParams.getStoreId());
            } else {
                SceneHelp.queryHandler(queryWrapper);
            }

            List<Department> departments = this.list(queryWrapper);

            List<DepartmentVO> all = this.initChild(departments);

            List<DepartmentVO> tree = new ArrayList<>();
            all.forEach(item -> {
                if ("0".equals(item.getParentId())) {
                    initChild(item, all);
                    tree.add(item);
                }
            });
            return tree;
        } catch (Exception e) {
            log.error("部门业务错误", e);
            return new ArrayList<>();
        }
    }

    private List<DepartmentVO> initChild(List<Department> all) {
        List<DepartmentVO> children = new ArrayList<>();
        if (all == null || all.isEmpty()) {
            return children;
        }
        all.forEach(item -> {
            if (!DEFAULT_PARENT_ID.equals(item.getParentId()) && all.stream().noneMatch(child -> child.getId().equals(item.getParentId()))) {
                QueryWrapper<Department> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("id", item.getParentId());
                children.addAll(this.initChild(this.list(queryWrapper)));
            }
            children.add(new DepartmentVO(item));
        });
        return children;
    }

    @Override
    public List<DepartmentVO> tree(String scene, String storeId) {
        try {
            QueryWrapper<Department> queryWrapper = new QueryWrapper<>();

            if (!UserContext.getCurrentUser().getScene().equals(SceneEnums.MANAGER)) {
                throw new ServiceException(ResultCode.ERROR, "您没有权限查看该部门");
            }

            queryWrapper.eq("scene", scene);
            queryWrapper.eq("extend_id", storeId);

            List<Department> departments = this.list(queryWrapper);

            List<DepartmentVO> all = new ArrayList<>();
            departments.forEach(item -> all.add(new DepartmentVO(item)));

            List<DepartmentVO> tree = new ArrayList<>();
            all.forEach(item -> {
                if ("0".equals(item.getParentId())) {
                    initChild(item, all);
                    tree.add(item);
                }
            });
            return tree;
        } catch (Exception e) {
            log.error("部门业务错误", e);
            return new ArrayList<>();
        }
    }

    @Override
    public Department getById(String id) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("id", id);
        SceneHelp.queryHandler(queryWrapper);
        return this.getOne(queryWrapper);
    }


    @Override
    @Transactional
    public void saveDepartment(Department department) {
        SceneHelp.objectHandler(department);
        this.checkDepartment(department.getTitle(), department.getParentId(), department.getScene(), department.getExtendId());

        this.saveOrUpdate(department);
    }

    @Override
    @Transactional
    public void updateDepartment(DepartmentEditDTO departmentEditDTO) {
        SceneHelp.objectHandler(departmentEditDTO);
        //判断是否有权限
        Department department = this.getById(departmentEditDTO.getId());

        if (!department.getTitle().equals(departmentEditDTO.getTitle())) {
            this.checkDepartment(departmentEditDTO.getTitle(), departmentEditDTO.getParentId(), departmentEditDTO.getScene(), departmentEditDTO.getExtendId());
        }

        //顶级部门不能修改上级部门
        if (DEFAULT_PARENT_ID.equals(department.getParentId()) && !DEFAULT_PARENT_ID.equals(departmentEditDTO.getParentId())) {
            throw new ServiceException(ResultCode.DEPARTMENT_PARENT_ERROR);
        }
        department.setTitle(departmentEditDTO.getTitle());
        department.setParentId(departmentEditDTO.getParentId());
        department.setSortOrder(departmentEditDTO.getSortOrder());
        department.setRoleIds(departmentEditDTO.getRoleIds());

        //上级部门不能是自己
        if (department.getId().equals(department.getParentId())) {
            throw new ServiceException(ResultCode.DEPARTMENT_PARENT_ERROR);
        }
        //更新部门信息
        this.saveOrUpdate(department);

    }

    private void checkDepartment(String title, String parentId, String scene, String extendId) {
        QueryWrapper<Department> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("title", title);
        queryWrapper.eq("parent_id", parentId);
        queryWrapper.eq("scene", scene);
        queryWrapper.eq("extend_id", extendId);
        if (this.count(queryWrapper) > 0) {
            throw new ServiceException(ResultCode.DEPARTMENT_EXIST_ERROR);
        }
    }


    @Override
    public void containRoleIds(List<String> roleIds) {
        QueryWrapper<Department> queryWrapper = new QueryWrapper<>();
        roleIds.forEach(item -> {
            queryWrapper.like(StringUtils.isNotEmpty(item), "role_ids", item).or();
        });
        if (this.count(queryWrapper) > 0) {
            throw new ServiceException(ResultCode.ROLE_BOUND_BY_DEPARTMENT);
        }
    }

    /**
     * 递归初始化子树
     *
     * @param tree          树结构
     * @param departmentVOS 数据库对象集合
     */
    private void initChild(DepartmentVO tree, List<DepartmentVO> departmentVOS) {
        departmentVOS.stream()
                .filter(item -> (item.getParentId().equals(tree.getId())))
                .forEach(child -> {
                    DepartmentVO childTree = new DepartmentVO(child);
                    initChild(childTree, departmentVOS);
                    tree.getChildren().add(childTree);
                });
    }


}